传统 Hal 开发指南5 ——

# 添加 aidl 文件

添加 aidl 文件 frameworks/base/core/java/android/os/IHelloService.aidl :

package android.os;

interface IHelloService
{
    void open();
    void write(String str);
    String read();
}
1
2
3
4
5
6
7
8

frameworks/base/Android.mk 中添加上 aidl 文件:

LOCAL_SRC_FILES += \
	core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl \
	core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl \
	core/java/android/accounts/IAccountManager.aidl \
	core/java/android/accounts/IAccountManagerResponse.aidl \
	core/java/android/accounts/IAccountAuthenticator.aidl \
      # .......
      core/java/android/os/IHelloService.aidl \ # 添加的内容
	core/java/android/security/IKeystoreService.aidl \
	core/java/android/service/carrier/ICarrierService.aidl
      # ......
1
2
3
4
5
6
7
8
9
10
11

# 实现服务端

添加 frameworks/base/services/core/java/com/android/server/HelloService.java 文件:

package com.android.server;

import android.os.IHelloService;

// 硬件服务的服务端实现
public class HelloService extends IHelloService.Stub {

    public native void natvieOpen();
    public native void natvieWrite(String str);
    public native String nativeRead();
  
    public void open() throws android.os.RemoteException {
        natvieOpen();
    }
  
    public void write(String str) throws android.os.RemoteException  {
        natvieWrite(str);
    }
  
    public String read() throws android.os.RemoteException  {
        return nativeRead();
    }


}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

# JNI 层实现

添加 frameworks/base/services/core/jni/com_android_server_HelloService.cpp JNI 实现:

#define LOG_TAG "HelloService"

#include <jni.h>
#include "JNIHelp.h"
#include "android_runtime/AndroidRuntime.h"

#include <utils/misc.h>
#include <utils/Log.h>
#include <hardware/hello_hal.h>

#include <stdio.h>
#include <string>

namespace android
{

static hw_module_t *gHelloModule = NULL;
static hello_hal_device_t *gHelloHalDevice = NULL;

static void helloOpen(JNIEnv env, jobject clazz)
{
    ALOGD("yuandaima_jni_open");
    if (gHelloModule != NULL) {
        return;
    }

    int err = hw_get_module(HELLO_HAL_HARDWARE_MODULE_ID, (hw_module_t const**)&gHelloModule);

    if (err) {
        ALOGE("Couldn't load %s module (%s)", HELLO_HAL_HARDWARE_MODULE_ID, strerror(-err));
    } else {
        if (gHelloModule) {
            ALOGD("yuandaima_jni_open get module sucess");
            hello_hal_methods_open(gHelloModule, &gHelloHalDevice);
        
        }
    }

    if(gHelloHalDevice) {
        gHelloHalDevice->hello_hal_open(gHelloHalDevice);
    }
}


static void helloWrite(JNIEnv* env, jobject clazz, jstring str)
{   
   
    if (gHelloHalDevice) {
         ALOGD("yuandaima_jni_write");
        const char * c_str = NULL;
        jboolean isCopy; 
	    c_str = env->GetStringUTFChars(str, &isCopy);   //从jstring指针中获取数据
        ALOGD("yuandaima_jni_write %s",c_str);
        gHelloHalDevice->hello_hal_write(gHelloHalDevice, c_str);
    } 
    else {
        ALOGW("Tried to hello but there is no hello device.");
    }
}

static jstring helloRead(JNIEnv* env, jobject clazz)
{
    if (gHelloHalDevice) {
        ALOGD("yuandaima_jni_read");
        char* data = NULL;
        gHelloHalDevice->hello_hal_read(gHelloHalDevice, &data);
        ALOGD("yuandaima_jni_read result is %s", data);
        if(data != NULL ) {
            // Android7 上直接用 NewStringUTF 把 char* 转 jstring 有乱码缺码 bug
            jbyteArray array = env->NewByteArray(1024);
            env->SetByteArrayRegion(array, 0, 1024,(const jbyte *)data);
            jstring strEncode = env->NewStringUTF("UTF-8");
            jclass cls = env->FindClass("java/lang/String");
            jmethodID ctor = env->GetMethodID(cls, "<init>", "([BLjava/lang/String;)V");
            jstring ret = (jstring) env->NewObject(cls, ctor, array, strEncode);
            return ret;
        }
    }
    return env->NewStringUTF("no msg");
}

    // public native void natvieOpen();
    // public native void natvieWrite(String str);
    // public native String nativeRead();

static const JNINativeMethod method_table[] = {
    { "natvieOpen", "()V", (void*)helloOpen },
    { "natvieWrite", "(Ljava/lang/String;)V", (void*)helloWrite },
    { "nativeRead", "()Ljava/lang/String;", (void*)helloRead }
};


int register_android_server_HelloService(JNIEnv *env)
{   
    ALOGD("yuandaima_jni_register");
    return jniRegisterNativeMethods(env, "com/android/server/HelloService",
            method_table, NELEM(method_table));
}

};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100

frameworks/base/services/core/jni/Android.mk 中添加:

LOCAL_SRC_FILES += \
      # ......
    $(LOCAL_REL_DIR)/com_android_server_UsbMidiDevice.cpp \
    $(LOCAL_REL_DIR)/com_android_server_UsbHostManager.cpp \
    $(LOCAL_REL_DIR)/com_android_server_VibratorService.cpp \
    $(LOCAL_REL_DIR)/com_android_server_HelloService.cpp \   # 添加的内容
    $(LOCAL_REL_DIR)/com_android_server_PersistentDataBlockService.cpp \
    $(LOCAL_REL_DIR)/onload.cpp
1
2
3
4
5
6
7
8

frameworks/base/services/core/jni/onload.cpp 中添加:

namespace android {
    // ......
    int register_android_server_vr_VrManagerService(JNIEnv* env);
    //添加的内容
    int register_android_server_HelloService(JNIEnv* env);
    int register_android_server_VibratorService(JNIEnv* env);
    int register_android_server_location_GnssLocationProvider(JNIEnv* env);
    int register_android_server_connectivity_Vpn(JNIEnv* env);
    // .....
}


// 在这里注册 JNI 函数
// java 层的 native 方法就能调用到对应的 native 层函数了
extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */)
{
    JNIEnv* env = NULL;
    jint result = -1;

    if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
        ALOGE("GetEnv failed!");
        return result;
    }
    ALOG_ASSERT(env, "Could not retrieve the env!");

    register_android_server_ActivityManagerService(env);
    register_android_server_PowerManagerService(env);
      // ......
    register_android_server_VibratorService(env);
     // 添加的内容
    register_android_server_HelloService(env);
    register_android_server_SystemServer(env);
    register_android_server_location_GnssLocationProvider(env);
    register_android_server_location_FlpHardwareProvider(env);
    // ......
    return JNI_VERSION_1_4;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

修改 frameworks/base/services/java/com/android/server/SystemServer.java:

    private void startBootstrapServices() {
            traceBeginAndSlog("StartHelloService");
            hello = new HelloService();
            ServiceManager.addService("HelloService", hello);
            Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
    }
1
2
3
4
5
6

# 客户端实现

添加一个接口 frameworks/base/core/java/android/os/HelloHal.java

package android.os;

import android.app.ActivityThread;
import android.content.Context;


public abstract class HelloHal {

    public HelloHal() {
    }

    public abstract int open() throws RemoteException;

    public abstract int write(String st) throws RemoteException;
  
    public abstract String read() throws RemoteException;
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

实现接口 frameworks/base/core/java/android/os/SystemHelloHal.java

package android.os;

import android.content.Context;
import android.util.Log;

/**
 * Vibrator implementation that controls the main system vibrator.
 *
 * @hide
 */
public class SystemHelloHal extends HelloHal {
  
    private static final String TAG = "HelloHal";

    private final IHelloService mService;

      // 获取Hello服务的代理端
    public SystemHelloHal() { 
        mService = IHelloService.Stub.asInterface(
                ServiceManager.getService("hello"));
    }

      // 通过代理端对象发起远程调用
    @Override
    public int open() throws RemoteException{
        if (mService != null) {
            mService.open();
        }

        return -1;
    }

    @Override
    public int write(String str) throws RemoteException {
        if (mService != null) {
            mService.write(str);
        }
        return -1;
    }
  
    @Override
    public String read() throws RemoteException {
        if (mService != null) {
            return mService.read();
        }
        return null;
    }

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49

frameworks/base/core/java/android/content/Context.java 中添加:

    public static final String HELLO_SERVICE = "hello";

        @StringDef(suffix = { "_SERVICE" }, value = {
            HELLO_SERVICE,  
            POWER_SERVICE,
            //......
1
2
3
4
5
6

最后在 SystemServiceRegistry 的静态块中添加:

// frameworks/base/core/java/android/app/SystemServiceRegistry.java
      static {
        registerService(Context.HELLO_SERVICE, HelloHal.class,
            new CachedServiceFetcher<HelloHal>() {
            @Override
            public HelloHal createService(ContextImpl ctx) {
                return new SystemHelloHal();
            }});
      }
1
2
3
4
5
6
7
8
9

# Selinux 配置

修改 system/sepolicy/service.te:

type HelloServiceType, app_api_service, system_server_service, service_manager_type;
1

修改 system/sepolicy/service_contexts:

HelloService                              u:object_r:HelloServiceType:s0
1

修改 system/sepolicy/platform_app.te,让系统 App 可以访问我们自定义的 Binder 服务:

allow platform_app HelloServiceType:service_manager find;
1

修改 system/sepolicy/untrusted_app.te,让普通 App 可以访问我们自定义的 Binder 服务:

allow untrusted_app HelloServiceType:service_manager find;
1

最后,让 SystemServer 可以访问到 hello 驱动,修改 system/sepolicy/system_server.te

allow system_server hello_dev_t:chr_file { open read write };
1

# 编译

source build/envsetup.sh
lunch aosp_x86_64-eng
# 在 com.android.server 包中添加了 HelloService 后,给系统添加了 API
make update-api
make -j32
# 启动模拟器
emulator -kernel /tmp/kernel-qemu/x86_64-3.10.0/kernel-qemu
1
2
3
4
5
6
7

# 参考资料

Android Native 开发之 NewString 与 NewStringUtf 解析 (opens new window)